#!/usr/bin/env python3
"""
FTP协议处理器
"""
import asyncio
import base64
import uuid
from datetime import datetime, timezone

from .base_handler import ProtocolHandler
from .logger import op_logger
from multihoneypot.attacklogger import attack_logger, AttackType, ProtocolType
class FTPHandler(ProtocolHandler):
    """
    FTP协议处理器，模拟FTP控制通道并记录客户端交互
    """

    def __init__(self, host, port, log_file):
        """
        初始化FTP处理器

        Args:
            host (str): 监听主机地址
            port (int): 监听端口
            log_file (str): 日志文件路径
        """
        super().__init__("ftp", host, port, log_file)

    async def start(self):
        """
        启动FTP服务器
        """
        # 创建异步服务器实例来处理客户端连接
        self._server = await asyncio.start_server(self._handle_client, host=self.host, port=self.port)
        addrs = ", ".join(str(sock.getsockname()) for sock in self._server.sockets)
        op_logger.info("FTP监听于 %s", addrs)
        # 启动服务器任务并返回任务对象
        return asyncio.create_task(self._server.serve_forever())

    async def _send_line(self, writer: asyncio.StreamWriter, line: str):
        """
        向客户端发送一行FTP响应

        Args:
            writer (asyncio.StreamWriter): 用于向连接写入数据的流写入器
            line (str): 要发送的响应行
        """
        writer.write((line + "\r\n").encode())
        await writer.drain()

    async def _handle_client(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        """
        处理FTP客户端连接

        Args:
            reader (asyncio.StreamReader): 用于从连接中读取数据的流读取器
            writer (asyncio.StreamWriter): 用于向连接写入数据的流写入器
        """
        # 初始化会话相关信息
        peer = writer.get_extra_info("peername") or ("unknown", 0)
        session_id = str(uuid.uuid4())
        start_ts = datetime.now(timezone.utc)
        raw_buf = bytearray()
        inputs = []
        username = None
        authenticated = False

        op_logger.info("FTP新连接 %s 会话=%s", peer, session_id)
        try:
            # 发送FTP欢迎消息
            await self._send_line(writer, "220 Microsoft FTP Service")
            while True:
                # 读取客户端输入行
                line = await reader.readline()
                if not line:
                    break
                raw_buf.extend(line)
                try:
                    text = line.decode(errors="ignore").rstrip("\r\n")
                except Exception:
                    text = "<无法解码>"
                inputs.append({"ts": datetime.now(timezone.utc).isoformat(), "input": text})
                op_logger.debug("FTP %s: %s", session_id, text)

                # 解析FTP命令和参数
                parts = text.split(" ", 1)
                cmd = parts[0].upper()
                arg = parts[1] if len(parts) > 1 else ""

                # 处理FTP命令
                if cmd == "USER":
                    username = arg
                    await self._send_line(writer, "331 Password required for " + username)
                elif cmd == "PASS":
                    # 记录认证尝试到攻击日志
                    attack_logger.log_auth_attempt(
                        source_ip=peer[0],
                        destination_port=self.port,
                        protocol=ProtocolType.FTP,
                        username=username,
                        password=arg
                    )

                    await self._send_line(writer, "230 User " + username + " logged in")
                    authenticated = True
                elif cmd == "SYST":
                    await self._send_line(writer, "215 UNIX Type: L8")
                elif cmd == "PWD":
                    await self._send_line(writer, '257 "/" is current directory')
                elif cmd == "CWD":
                    await self._send_line(writer, "250 CWD command successful")
                elif cmd == "LIST":
                    # 无数据连接：发送预设的成功消息
                    await self._send_line(writer, "150 Opening ASCII mode data connection for file list")
                    await self._send_line(writer, "226 Transfer complete")
                elif cmd in ("RETR", "STOR"):
                    # 记录文件访问到攻击日志
                    attack_logger.log_file_access(
                        source_ip=peer[0],
                        destination_port=self.port,
                        protocol=ProtocolType.FTP,
                        file_path=arg,
                        access_type="read" if cmd == "RETR" else "write"
                    )

                    # 出于安全原因拒绝实际传输
                    await self._send_line(writer, "550 Action not taken (simulated)")
                elif cmd == "QUIT":
                    await self._send_line(writer, "221 Goodbye.")
                    break
                else:
                    await self._send_line(writer, "502 Command not implemented")
        except asyncio.CancelledError:
            op_logger.info("FTP会话已取消 %s", session_id)
        except Exception as e:
            op_logger.exception("FTP处理器错误 %s: %s", session_id, e)
        finally:
            # 构建并保存会话日志条目
            entry = {
                "session_id": session_id,
                "start_time": start_ts.isoformat(),
                "end_time": datetime.now(timezone.utc).isoformat(),
                "duration_seconds": (datetime.now(timezone.utc) - start_ts).total_seconds(),
                "remote_ip": peer[0],
                "remote_port": peer[1],
                "username": username,
                "authenticated": authenticated,
                "inputs": inputs,
                "raw_base64": base64.b64encode(bytes(raw_buf)).decode("ascii"),
            }
            await self.persist(entry)
            try:
                writer.close()
                await writer.wait_closed()
            except Exception:
                pass
            op_logger.info("FTP关闭会话 %s 来自 %s", session_id, peer)
